home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 001-025 / disk_023 / ver30 / echo.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  9KB  |  450 lines

  1. /*
  2.  * Name:    MicroEMACS
  3.  *        Echo line reading and writing.
  4.  * Version:    29
  5.  * Last edit:    14-Feb-86
  6.  * By:        rex::conroy
  7.  *        decvax!decwrl!dec-rhea!dec-rex!conroy
  8.  *
  9.  * Common routines for reading
  10.  * and writing characters in the echo line area
  11.  * of the display screen. Used by the entire
  12.  * known universe.
  13.  */
  14. #include    "def.h"
  15.  
  16. int    epresf    = FALSE;        /* Stuff in echo line flag.    */
  17. int    nmsg    = 0;            /* Size of occupied msg. area.    */
  18. int    curmsgf    = FALSE;        /* Current alert state.        */
  19. int    newmsgf    = FALSE;        /* New alert state.        */
  20.  
  21. char    msg[NMSG];            /* Random message storage.    */
  22.  
  23. /*
  24.  * Send a string to the message system.
  25.  * Add a free newline to the end of the message string.
  26.  * Return TRUE if it fits, and FALSE if it does not.
  27.  * Perhaps the message buffer should know how to get
  28.  * larger, just like the kill buffer?
  29.  */
  30. writemsg(sp)
  31. register char    *sp;
  32. {
  33.     register int    c;
  34.  
  35.     if (nmsg+strlen(sp)+1 > NMSG)        /* "+1" for the "\n".    */
  36.         return (FALSE);
  37.     while ((c = *sp++) != '\0')
  38.         msg[nmsg++] = c;
  39.     msg[nmsg++] = '\n';
  40.     newmsgf = TRUE;                /* Update mode line.    */
  41.     return (TRUE);
  42. }
  43.  
  44. /*
  45.  * Read messages. The message lines are
  46.  * displayed, one line at a time, in the message line.
  47.  * A special sub-mode is entered, in which the keys have
  48.  * the following meanings:
  49.  *    ^P    Go backward 1 line.
  50.  *    BS    Go backward 1 line.
  51.  *    ^N    Go forward 1 line. Quit if at the end.
  52.  *    SP    Go forward 1 line. Quit if at the end.
  53.  *    CR    Go forward 1 line. Quit if at the end.
  54.  *    ^G    Abort, leave old text.
  55.  *    ^C    Quit, delete anything already read.
  56.  * Return TRUE if you left this mode in a reasonable
  57.  * way (not ^G), and ABORT if you quit the mode with a
  58.  * ^G.
  59.  */
  60. readmsg()
  61. {
  62.     register int    c;
  63.     register int    i;
  64.     register int    j;
  65.  
  66.     if (nmsg == 0)                /* Duck out if none.    */
  67.         return (TRUE);
  68.     newmsgf = FALSE;            /* Kill alert, and do    */
  69.     update();                /* a redisplay.        */
  70.     ttcolor(CTEXT);
  71.     i = 0;
  72.     while (i < nmsg) {
  73.         ttmove(nrow-1, 0);        /* Display 1 line.    */
  74.         while (i<nmsg && (c=msg[i++])!='\n')
  75.             eputc(c);
  76.         tteeol();
  77.         ttmove(nrow-1, 0);        /* Looks nice.        */
  78.         ttflush();
  79.         for (;;) {            /* Editing loop.    */
  80.             c = ttgetc();
  81.             switch (c) {
  82.             case 0x0E:        /* ^N            */
  83.             case 0x20:        /* SP            */
  84.             case 0x0D:        /* CR            */
  85.                 break;
  86.  
  87.             case 0x10:        /* ^P            */
  88.             case 0x08:        /* BS            */
  89.                 do {
  90.                     --i;
  91.                 } while (i!=0 && msg[i-1]!='\n');
  92.                 if (i != 0) {
  93.                     do {    /* Back up 1 line.    */
  94.                         --i;
  95.                     } while (i!=0 && msg[i-1]!='\n');
  96.                 }
  97.                 break;
  98.  
  99.             case 0x03:        /* ^C            */
  100.                 j = 0;        /* Eat what we read.    */
  101.                 while (i < nmsg)
  102.                     msg[j++] = msg[i++];
  103.                 nmsg = j;
  104.                 eerase();
  105.                 return (TRUE);
  106.  
  107.             case 0x07:        /* ^G            */
  108.                 ttbeep();
  109.                 eerase();
  110.                 return (ABORT);
  111.  
  112.             default:        /* Loop on the rest.    */
  113.                 continue;
  114.             }
  115.             break;
  116.         }                
  117.     }    
  118.     nmsg = 0;                /* Flow off the end.    */
  119.     eerase();
  120.     return (TRUE);
  121. }
  122.  
  123. /*
  124.  * Erase the echo line.
  125.  */
  126. eerase()
  127. {
  128.     ttcolor(CTEXT);
  129.     ttmove(nrow-1, 0);
  130.     tteeol();
  131.     ttflush();
  132.     epresf = FALSE;
  133. }
  134.  
  135. /*
  136.  * Ask "yes" or "no" question.
  137.  * Return ABORT if the user answers the question
  138.  * with the abort ("^G") character. Return FALSE
  139.  * for "no" and TRUE for "yes". No formatting
  140.  * services are available.
  141.  */
  142. eyesno(sp)
  143. char    *sp;
  144. {
  145.     register int    s;
  146.     char        buf[64];
  147.  
  148.     for (;;) {
  149.         s = ereply("%s [y/n]? ", buf, sizeof(buf), sp);
  150.         if (s == ABORT)
  151.             return (ABORT);
  152.         if (s != FALSE) {
  153.             if (buf[0]=='y' || buf[0]=='Y')
  154.                 return (TRUE);
  155.             if (buf[0]=='n' || buf[0]=='N')
  156.                 return (FALSE);
  157.         }
  158.     }
  159. }
  160.  
  161. /*
  162.  * Write out a prompt, and read back a
  163.  * reply. The prompt is now written out with full "eprintf"
  164.  * formatting, although the arguments are in a rather strange
  165.  * place. This is always a new message, there is no auto
  166.  * completion, and the return is echoed as such.
  167.  */
  168. /* VARARGS3 */
  169. ereply(fp, buf, nbuf, arg)
  170. char    *fp;
  171. char    *buf;
  172. {
  173.     return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
  174. }
  175.  
  176. /*
  177.  * This is the general "read input from the
  178.  * echo line" routine. The basic idea is that the prompt
  179.  * string "prompt" is written to the echo line, and a one
  180.  * line reply is read back into the supplied "buf" (with
  181.  * maximum length "len"). The "flag" contains EFNEW (a
  182.  * new prompt), an EFAUTO (autocomplete), or EFCR (echo
  183.  * the carriage return as CR).
  184.  */
  185. eread(fp, buf, nbuf, flag, ap)
  186. char    *fp;
  187. char    *buf;
  188. char    *ap;
  189. {
  190.     register int    cpos;
  191.     register SYMBOL    *sp1;
  192.     register SYMBOL    *sp2;
  193.     register int    i;
  194.     register int    c;
  195.     register int    h;
  196.     register int    nhits;
  197.     register int    nxtra;
  198.     register int    bxtra;
  199.  
  200.     cpos = 0;
  201.     if (kbdmop != NULL) {            /* In a macro.        */
  202.         while ((c = *kbdmop++) != '\0')
  203.             buf[cpos++] = c;
  204.         buf[cpos] = '\0';
  205.         goto done;
  206.     }
  207.     if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
  208.         ttcolor(CTEXT);
  209.         ttmove(nrow-1, 0);
  210.         epresf = TRUE;
  211.     } else
  212.         eputc(' ');
  213.     eformat(fp, ap);
  214.     tteeol();
  215.     ttflush();
  216.     for (;;) {
  217.         c = ttgetc();
  218.         if (c==' ' && (flag&EFAUTO)!=0) {
  219.             nhits = 0;
  220.             nxtra = HUGE;
  221.             for (h=0; h<NSHASH; ++h) {
  222.                 sp1 = symbol[h];
  223.                 while (sp1 != NULL) {
  224.                     for (i=0; i<cpos; ++i) {
  225.                         if (buf[i] != sp1->s_name[i])
  226.                             break;
  227.                     }
  228.                     if (i == cpos) {
  229.                         if (nhits == 0)
  230.                             sp2 = sp1;
  231.                         ++nhits;
  232.                         bxtra = getxtra(sp1, sp2, cpos);
  233.                         if (bxtra < nxtra)
  234.                             nxtra = bxtra;
  235.                     }
  236.                     sp1 = sp1->s_symp;
  237.                 }
  238.             }
  239.             if (nhits == 0)        /* No completion.    */
  240.                 continue;
  241.             for (i=0; i<nxtra && cpos<nbuf-1; ++i) {
  242.                 c = sp2->s_name[cpos];
  243.                 buf[cpos++] = c;
  244.                 eputc(c);
  245.             }
  246.             ttflush();
  247.             if (nhits != 1)        /* Fake a CR if there    */
  248.                 continue;    /* is 1 choice.        */
  249.             c = 0x0D;
  250.         }
  251.         switch (c) {
  252.         case 0x0D:            /* Return, done.    */
  253.             buf[cpos] = '\0';
  254.             if (kbdmip != NULL) {
  255.                 if (kbdmip+cpos+1 > &kbdm[NKBDM-3]) {
  256.                     (void) ctrlg(FALSE, 0, KRANDOM);
  257.                     ttflush();
  258.                     return (ABORT);
  259.                 }
  260.                 for (i=0; i<cpos; ++i)
  261.                     *kbdmip++ = buf[i];
  262.                 *kbdmip++ = '\0';
  263.             }
  264.             if ((flag&EFCR) != 0) {
  265.                 ttputc(0x0D);
  266.                 ttflush();
  267.             }
  268.             goto done;
  269.  
  270.         case 0x07:            /* Bell, abort.        */
  271.             eputc(0x07);
  272.             (void) ctrlg(FALSE, 0, KRANDOM);
  273.             ttflush();
  274.             return (ABORT);
  275.  
  276.         case 0x7F:            /* Rubout, erase.    */
  277.         case 0x08:            /* Backspace, erase.    */
  278.             if (cpos != 0) {
  279.                 ttputc('\b');
  280.                 ttputc(' ');
  281.                 ttputc('\b');
  282.                 --ttcol;
  283.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  284.                     ttputc('\b');
  285.                     ttputc(' ');
  286.                     ttputc('\b');
  287.                     --ttcol;
  288.                 }
  289.                 ttflush();
  290.             }
  291.             break;
  292.  
  293.         case 0x15:            /* C-U, kill line.    */
  294.             while (cpos != 0) {
  295.                 ttputc('\b');
  296.                 ttputc(' ');
  297.                 ttputc('\b');
  298.                 --ttcol;
  299.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  300.                     ttputc('\b');
  301.                     ttputc(' ');
  302.                     ttputc('\b');
  303.                     --ttcol;
  304.                 }
  305.             }
  306.             ttflush();
  307.             break;
  308.  
  309.         default:            /* All the rest.    */
  310.             if (cpos < nbuf-1) {
  311.                 buf[cpos++] = c;
  312.                 eputc(c);
  313.                 ttflush();
  314.             }
  315.         }
  316.     }
  317. done:
  318.     if (buf[0] == '\0')
  319.         return (FALSE);
  320.     return (TRUE);
  321. }
  322.  
  323. /*
  324.  * The "sp1" and "sp2" point to extended command
  325.  * symbol table entries. The "cpos" is a horizontal position
  326.  * in the name. Return the longest block of characters that can
  327.  * be autocompleted at this point. Sometimes the two symbols
  328.  * are the same, but this is normal.
  329.  */
  330. getxtra(sp1, sp2, cpos)
  331. register SYMBOL    *sp1;
  332. register SYMBOL    *sp2;
  333. {
  334.     register int    i;
  335.  
  336.     i = cpos;
  337.     for (;;) {
  338.         if (sp1->s_name[i] != sp2->s_name[i])
  339.             break;
  340.         if (sp1->s_name[i] == '\0')
  341.             break;
  342.         ++i;
  343.     }
  344.     return (i - cpos);
  345. }
  346.  
  347. /*
  348.  * Special "printf" for the echo line.
  349.  * Each call to "eprintf" starts a new line in the
  350.  * echo area, and ends with an erase to end of the
  351.  * echo line. The formatting is done by a call
  352.  * to the standard formatting routine.
  353.  */
  354. /* VARARGS1 */
  355. eprintf(fp, arg)
  356. char    *fp;
  357. {
  358.     ttcolor(CTEXT);
  359.     ttmove(nrow-1, 0);
  360.     eformat(fp, (char *)&arg);
  361.     tteeol();
  362.     ttflush();
  363.     epresf = TRUE;
  364. }
  365.  
  366. /*
  367.  * Printf style formatting. This is
  368.  * called by both "eprintf" and "ereply", to provide
  369.  * formatting services to their clients. The move to the
  370.  * start of the echo line, and the erase to the end of
  371.  * the echo line, is done by the caller.
  372.  */
  373. eformat(fp, ap)
  374. register char    *fp;
  375. register char    *ap;
  376. {
  377.     register int    c;
  378.  
  379.     while ((c = *fp++) != '\0') {
  380.         if (c != '%')
  381.             eputc(c);
  382.         else {
  383.             c = *fp++;
  384.             switch (c) {
  385.             case 'd':
  386.                 eputi(*(int *)ap, 10);
  387.                 ap += sizeof(int);
  388.                 break;
  389.  
  390.             case 'o':
  391.                 eputi(*(int *)ap,  8);
  392.                 ap += sizeof(int);
  393.                 break;
  394.  
  395.             case 's':
  396.                 eputs(*(char **)ap);
  397.                 ap += sizeof(char *);
  398.                 break;
  399.  
  400.             default:
  401.                 eputc(c);
  402.             }
  403.         }
  404.     }
  405. }
  406.  
  407. /*
  408.  * Put integer, in radix "r".
  409.  */
  410. eputi(i, r)
  411. register int    i;
  412. register int    r;
  413. {
  414.     register int    q;
  415.  
  416.     if ((q=i/r) != 0)
  417.         eputi(q, r);
  418.     eputc(i%r+'0');
  419. }
  420.  
  421. /*
  422.  * Put string.
  423.  */
  424. eputs(s)
  425. register char    *s;
  426. {
  427.     register int    c;
  428.  
  429.     while ((c = *s++) != '\0')
  430.         eputc(c);
  431. }
  432.  
  433. /*
  434.  * Put character. Watch for
  435.  * control characters, and for the line
  436.  * getting too long.
  437.  */
  438. eputc(c)
  439. register int    c;
  440. {
  441.     if (ttcol < ncol) {
  442.         if (ISCTRL(c) != FALSE) {
  443.             eputc('^');
  444.             c ^= 0x40;
  445.         }
  446.         ttputc(c);
  447.         ++ttcol;
  448.     }
  449. }
  450.